package com.buli.blmall.generator.core;

import com.buli.blmall.generator.config.DataSourceConfig;
import com.buli.blmall.generator.config.GeneratorConfig;
import com.buli.blmall.generator.convert.MetaDataConvert;
import com.buli.blmall.generator.metadata.MetaTable;
import com.buli.blmall.generator.metadata.MetaWrapper;
import com.buli.blmall.generator.metadata.TableInfo;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;

import java.io.File;
import java.io.FileWriter;
import java.nio.file.Paths;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;

/**
 * 自定义代码生成器
 * @author xiang.gao
 * @date 2024/12/5 14:34
 */
public class CodeGenerator {

    private static String UTF8 = "UTF-8";
    private GeneratorConfig generatorConfig;

    public static CodeGenerator config(GeneratorConfig generatorConfig) {
        return new CodeGenerator(generatorConfig);
    }

    private CodeGenerator(GeneratorConfig generatorConfig) {
        this.generatorConfig = generatorConfig;
    }

    /**
     * 加载模板引擎
     */
    private void initTemplate() {
        Properties properties = new Properties();
        properties.setProperty("resource.loader.file.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
        properties.setProperty(Velocity.INPUT_ENCODING, UTF8);
        Velocity.init(properties);
    }

    /**
     * 读取模板路径
     * @param entityName
     * @return
     */
    private Map<String, String> getTemplateMap(String entityName) {
        Map<String, String> templateList = new LinkedHashMap();
        templateList.put("template/entity.java.vm", entityName.concat(".java"));
        templateList.put("template/mapper.java.vm", entityName.concat("Mapper.java"));
        templateList.put("template/service.java.vm", entityName.concat("Service.java"));
        templateList.put("template/controller.java.vm", entityName.concat("Controller.java"));
        templateList.put("template/mapper.xml.vm", entityName.concat("Mapper.xml"));
        templateList.put("template/vo.java.vm", entityName.concat("Vo.java"));
        return templateList;
    }

    /**
     * 开始生成
     */
    public void start() {
        System.out.println("----------------- 开始生成文件 --------------------");

        //加载模板引擎
        initTemplate();

        //读取表数据
        TableInfo tableInfo = getTableInfo();

        //设置模板变量
        VelocityContext velocityContext = ContextLoader.loadContext(tableInfo, generatorConfig);

        // 文件生成
        getTemplateMap(tableInfo.getEntityName()).forEach((templatePath, fileName) -> writerFile(templatePath, fileName,  velocityContext));

        System.out.println("------------------- 生成文件完毕 --------------------");
    }

    /**
     * 输出文件
     * @param templatePath
     * @param fileName
     * @param velocityContext
     */
    private void writerFile(String templatePath, String fileName, VelocityContext velocityContext) {
        try {
            String filePath = generateFilePath(fileName, templatePath);
            FileWriter sw = new FileWriter(filePath);
            Template template = Velocity.getTemplate(templatePath, UTF8);
            template.merge(velocityContext, sw);
            sw.close();
            System.out.println(String.format("成功生成文件:%s", filePath));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 生成文件路径
     * @param fileName
     * @param templatePath
     * @return
     */
    private String generateFilePath(String fileName, String templatePath) {
        // mapper
        String packageName = templatePath.split("/")[1].split("\\.")[0];
        String suffix = templatePath.split("\\.")[1];
        String outputDir = getOutputDir(packageName, suffix);
        File directory = new File(outputDir);
        directory.deleteOnExit();
        directory.mkdirs();
        return outputDir + fileName;
    }

    /**
     * 输出目录
     * @param packageName
     * @param suffix
     * @return
     */
    private String getOutputDir(String packageName, String suffix) {
        StringBuffer outputDir = new StringBuffer();
        outputDir.append(Paths.get(System.getProperty("user.dir"))).append(File.separator).
                append(generatorConfig.getTaggetProject()).append(File.separator);
        outputDir.append("src").append(File.separator).append("main").append(File.separator);
        if ("xml".equals(suffix)) {
            outputDir.append("resources").append(File.separator)
                    .append(packageName).append(File.separator).append(generatorConfig.getMoudleName());
        } else {
            outputDir.append("java").append(File.separator)
                    .append(generatorConfig.getBasePackage().replace(".", File.separator)).append(File.separator)
                    .append(generatorConfig.getMoudleName()).append(File.separator).append(packageName);
        }
        return outputDir.append(File.separator).toString();
    }

    /**
     * 读取表元数据
     * @return
     */
    private TableInfo getTableInfo() {
        MetaWrapper metaWrapper = null;
        try {
            DataSourceConfig dataSourceConfig = generatorConfig.getDataSourceConfig();
            String databaseName = getDatabaseName(generatorConfig.getDataSourceConfig().getUrl());

            metaWrapper = MetaWrapper.init(dataSourceConfig);
            MetaTable.Table table = metaWrapper.getTable(databaseName, generatorConfig.getTableName());

            return MetaDataConvert.metaDataConvert(table);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (metaWrapper != null) {
                metaWrapper.closeConnection();
            }
        }
    }

    private String getDatabaseName(String jdbcUrl) {
        String url = jdbcUrl.split("\\?")[0];
        return url.substring(url.lastIndexOf("/") + 1);
    }

}
